// function main() {
//   var canvas = document.getElementById('android3D');

//   var gl = WebGLUtils.setupWebGL(canvas);
//   if (!gl) {
//     console.log('Failed to get the rendering context for WebGL');
//     return;
//   }


//   gl.clearColor(0.0, 0.0, 0.0, 0.0);
//   gl.enable(gl.DEPTH_TEST);
//   gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

//   var draw3D0 = new Draw3D(gl, 'cyclinder');


//   draw3D0.drawCylinder(
//       gl, [0, 1, 0, 1], [0, -1, 0, 1], 1, [52 / 0xFF, 168 / 0xFF, 83 /
//       0xFF]);



//   //   document.onkeydown = function(ev) {
//   //     if (ev.keyCode == 37) {  // left
//   //       gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//   //     } else if (ev.keyCode == 39) {  // right
//   //       gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//   //       draw3D0.updateCylinder(gl, [0, 1, 0, 1], [0, -1, 0, 1]);
//   //       draw3D1.updateBall(gl, [0, -3, 0, 1], [1, 1, 0]);

//   //     } else if (ev.keyCode == 38) {  // uplocation
//   //       gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//   //       draw3D1.drawBall(
//   //           gl, [0, -2, 0, 1], [1, 1, 0], 0.5, 1,
//   //           [52 / 0xFF, 168 / 0xFF, 83 / 0xFF]);
//   //       draw3D0.drawCylinder(
//   //           gl, [0, 1, 0, 1], [0, -1, 0, 1], 1,
//   //           [52 / 0xFF, 168 / 0xFF, 83 / 0xFF]);

//   //     } else {
//   //       return;
//   //     }
//   //   };
// }

/**
 * Draw3D的构造函数
 */

// type为'cyclinder','ball','objFile'
var Draw3D = function(gl, type, texture) {
  this.type = type;

  if (type == 'objFile') {
    this.program =
        createProgram(gl, this.OBJ_VSHADER_SOURCE, this.OBJ_FSHADER_SOURCE1);
  }
  if (type == 'ball' && texture == null) {
    this.program = createProgram(gl, this.VSHADER_SOURCE, this.FSHADER_SOURCE1);
    this.program.a_ColorOrTex =
        gl.getAttribLocation(this.program, 'a_ColorOrTex');
  } else {
    this.program = createProgram(gl, this.VSHADER_SOURCE, this.FSHADER_SOURCE);
    this.program.a_ColorOrTex =
        gl.getAttribLocation(this.program, 'a_ColorOrTex');
  }

  if (!this.program) {
    console.log('Failed to intialize shaders.');
    return;
  }
  this.program.a_Position = gl.getAttribLocation(this.program, 'a_Position');
  this.program.a_Color = gl.getAttribLocation(this.program, 'a_Color');
  this.program.a_Normal = gl.getAttribLocation(this.program, 'a_Normal');
  this.program.u_ModelMatrix =
      gl.getUniformLocation(this.program, 'u_ModelMatrix');
  this.program.u_MvpMatrix = gl.getUniformLocation(this.program, 'u_MvpMatrix');
  this.program.u_NormalMatrix =
      gl.getUniformLocation(this.program, 'u_NormalMatrix');
  this.program.u_LightColor =
      gl.getUniformLocation(this.program, 'u_LightColor');
  this.program.u_LightPosition =
      gl.getUniformLocation(this.program, 'u_LightPosition');
  this.program.u_AmbientLight =
      gl.getUniformLocation(this.program, 'u_AmbientLight');



  if (!this.program.u_ModelMatrix || !this.program.u_MvpMatrix ||
      !this.program.u_NormalMatrix || !this.program.u_LightColor ||
      !this.program.u_LightPosition || !this.program.u_AmbientLight) {
    console.log('Failed to get the storage location');
    return;
  }
  if (texture) {
    this.texture = texture;
    this.program.a_TexCoord = gl.getAttribLocation(this.program, 'a_TexCoord');
    this.program.u_Sampler = gl.getUniformLocation(this.program, 'u_Sampler');
    var image = document.getElementById(texture);
    console.log(image);
    this.configureTexture(gl, image);
  }


  this.lookat = new Array(0, 2, 20, 0, 0, 0, 0, 1, 0);
};
/**
 * 可设置的变量
 */
//图形类型,type为'cyclinder'或'ball'
Draw3D.prototype.type = null;
Draw3D.prototype.texture = null;

/**
 * 圆柱的两个圆心
 */
Draw3D.prototype.cyclinderVertice1;
Draw3D.prototype.cyclinderVertice2;
/**
 * 球的中心点和上方向
 */
Draw3D.prototype.ballVertice;
Draw3D.prototype.ballVector;
//视点
Draw3D.prototype.lookat;

//投影
Draw3D.prototype.perspective = new Array(30, 1, 1, 100);
//图形变换矩阵，可以使图形进行变化
Draw3D.prototype.MODEL_MATRIX = new Matrix4();

Draw3D.prototype.setModelMatrix = function(modelMatrix) {
  this.MODEL_MATRIX = modelMatrix;
};


Draw3D.prototype.texture;
//着色器的程序对象
Draw3D.prototype.program;
/**
 * 缓存区对象
 */
Draw3D.prototype.vertexBuffer;
Draw3D.prototype.colorBuffer;
Draw3D.prototype.normalBuffer;
Draw3D.prototype.indexBuffer;
Draw3D.prototype.texCoordBuffer;
Draw3D.prototype.colorOrTexBuffer;
Draw3D.prototype.numIndices;
//顶点着色器
Draw3D.prototype.VSHADER_SOURCE = 'attribute vec4 a_Position;\n' +
    'attribute vec4 a_Color;\n' +   //物体颜色
    'attribute vec4 a_Normal;\n' +  //法向量
    'attribute vec2 a_TexCoord;\n' +
    'attribute float a_ColorOrTex;\n' +
    'uniform mat4 u_MvpMatrix;\n' +     //模型视图投影矩阵
    'uniform mat4 u_ModelMatrix;\n' +   // 模型矩阵
    'uniform mat4 u_NormalMatrix;\n' +  // 法向量变换矩阵
    'varying vec4 v_Color;\n' +
    'varying vec3 v_Normal;\n' +
    'varying vec2 v_TexCoord;\n' +
    'varying float v_ColorOrTex;\n' +
    'varying vec3 v_Position;\n' +
    'void main() {\n' +
    '  gl_Position = u_MvpMatrix * a_Position;\n' +
    // 计算世界坐标下的定点坐标
    '  v_Position = vec3(u_ModelMatrix * a_Position);\n' +
    '  v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +
    '  v_Color = a_Color;\n' +
    '  v_TexCoord = a_TexCoord;\n' +
    '  v_ColorOrTex = a_ColorOrTex;\n' +
    '}\n';

// 片元着色器
Draw3D.prototype.FSHADER_SOURCE = '#ifdef GL_ES\n' +
    'precision mediump float;\n' +
    '#endif\n' +
    'uniform vec3 u_LightColor;\n' +     // 光照颜色
    'uniform vec3 u_LightPosition;\n' +  // 光的位置
    'uniform vec3 u_AmbientLight;\n' +   // 环境光的颜色
    'uniform sampler2D u_Sampler;\n' +
    'varying vec3 v_Normal;\n' +
    'varying vec3 v_Position;\n' +
    'varying vec2 v_TexCoord;\n' +
    'varying float v_ColorOrTex;\n' +
    'varying vec4 v_Color;\n' +  //物体颜色
    'void main() {\n' +

    'vec4 color;\n' +

    'if(v_ColorOrTex==1.0) {\n' +
    ' color = texture2D(u_Sampler, v_TexCoord);\n' +
    '}else{\n' +
    ' color = v_Color;}\n' +
    // 对法线进行归一化
    '  vec3 normal = normalize(v_Normal);\n' +
    // 计算光线方向并归一化
    '  vec3 lightDirection = normalize(u_LightPosition - v_Position);\n' +
    // 计算光线方向和法向量的点积
    '  float nDotL = max(dot(lightDirection, normal), 0.0);\n' +
    // // 计算光照效果和环境光照效果
    // '  vec4 color = texture2D(u_Sampler, v_TexCoord);\n' +
    '  vec3 diffuse = u_LightColor * color.rgb * nDotL;\n' +
    '  vec3 ambient = u_AmbientLight * color.rgb;\n' +
    //计算最终光照效果

    // '  gl_FragColor = vec4(color.rgb * nDotL, color.a);\n' +
    '  gl_FragColor = vec4(diffuse + ambient, color.a);\n' +
    '}\n';
//顶点着色器
Draw3D.prototype.OBJ_VSHADER_SOURCE = 'attribute vec4 a_Position;\n' +
    'attribute vec4 a_Color;\n' +   //物体颜色
    'attribute vec4 a_Normal;\n' +  //法向量
    'attribute vec2 a_TexCoord;\n' +
    'uniform mat4 u_MvpMatrix;\n' +     //模型视图投影矩阵
    'uniform mat4 u_ModelMatrix;\n' +   // 模型矩阵
    'uniform mat4 u_NormalMatrix;\n' +  // 法向量变换矩阵
    'varying vec4 v_Color;\n' +
    'varying vec3 v_Normal;\n' +
    'varying vec2 v_TexCoord;\n' +
    'varying vec3 v_Position;\n' +
    'void main() {\n' +
    '  gl_Position = u_MvpMatrix * a_Position;\n' +
    // 计算世界坐标下的定点坐标
    '  v_Position = vec3(u_ModelMatrix * a_Position);\n' +
    '  v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +
    '  v_Color = a_Color;\n' +
    '  v_TexCoord = a_TexCoord;\n' +
    '}\n';

// 片元着色器
Draw3D.prototype.OBJ_FSHADER_SOURCE = '#ifdef GL_ES\n' +
    'precision mediump float;\n' +
    '#endif\n' +
    'uniform vec3 u_LightColor;\n' +     // 光照颜色
    'uniform vec3 u_LightPosition;\n' +  // 光的位置
    'uniform vec3 u_AmbientLight;\n' +   // 环境光的颜色
    'uniform sampler2D u_Sampler;\n' +
    'varying vec3 v_Normal;\n' +
    'varying vec3 v_Position;\n' +
    'varying vec2 v_TexCoord;\n' +

    'varying vec4 v_Color;\n' +  //物体颜色
    'void main() {\n' +

    'vec4 color;\n' +
    ' color = v_Color;\n' +
    // 对法线进行归一化
    '  vec3 normal = normalize(v_Normal);\n' +
    // 计算光线方向并归一化
    '  vec3 lightDirection = normalize(u_LightPosition - v_Position);\n' +
    // 计算光线方向和法向量的点积
    '  float nDotL = max(dot(lightDirection, normal), 0.0);\n' +
    // // 计算光照效果和环境光照效果
    // '  vec4 color = texture2D(u_Sampler, v_TexCoord);\n' +
    '  vec3 diffuse = u_LightColor * color.rgb * nDotL;\n' +
    '  vec3 ambient = u_AmbientLight * color.rgb;\n' +
    //计算最终光照效果

    // '  gl_FragColor = vec4(color.rgb * nDotL, color.a);\n' +
    '  gl_FragColor = vec4(diffuse + ambient, color.a);\n' +
    '}\n';

// 片元着色器
Draw3D.prototype.FSHADER_SOURCE1 = '#ifdef GL_ES\n' +
    'precision mediump float;\n' +
    '#endif\n' +
    'uniform vec3 u_LightColor;\n' +     // 光照颜色
    'uniform vec3 u_LightPosition;\n' +  // 光的位置
    'uniform vec3 u_AmbientLight;\n' +   // 环境光的颜色
    'uniform sampler2D u_Sampler;\n' +
    'varying vec3 v_Normal;\n' +
    'varying vec3 v_Position;\n' +
    'varying vec2 v_TexCoord;\n' +
    'varying float v_ColorOrTex;\n' +
    'varying vec4 v_Color;\n' +  //物体颜色
    'void main() {\n' +

    'vec4 color = v_Color;\n' +

    'if(v_ColorOrTex==1.0) {\n' +
    ' color = v_Color;\n' +
    '}\n' +
    // ' color = v_Color;}\n' +
    // 对法线进行归一化
    '  vec3 normal = normalize(v_Normal);\n' +
    // 计算光线方向并归一化
    '  vec3 lightDirection = normalize(u_LightPosition - v_Position);\n' +
    // 计算光线方向和法向量的点积
    '  float nDotL = max(dot(lightDirection, normal), 0.0);\n' +
    // // 计算光照效果和环境光照效果
    // '  vec4 color = texture2D(u_Sampler, v_TexCoord);\n' +
    '  vec3 diffuse = u_LightColor * color.rgb * nDotL;\n' +
    '  vec3 ambient = u_AmbientLight * color.rgb;\n' +
    //计算最终光照效果

    // '  gl_FragColor = vec4(color.rgb * nDotL, color.a);\n' +
    '  gl_FragColor = vec4(diffuse + ambient, color.a);\n' +
    '}\n';
Draw3D.prototype.objLoad;
Draw3D.prototype.drawByObjFile = function(fileName) {
  console.log('draw objfile');
  if (this.type != 'objFile') {
    console.log('Type is not objFile');
    return;
  }
  this.objLoad = new OBJLoad();

  this.objLoad.readOBJFile(fileName, 10, true);

  this.updateByObjFile();
};
Draw3D.prototype.onReadComplete = function(gl) {
  var drawingInfo = this.objLoad.g_objDoc.getDrawingInfo();

  //将数据传入缓存区，并交给buffer对象保存相关数据
  this.vertexBuffer =
      this.initBufferForObj(gl, drawingInfo.vertices, 3, gl.FLOAT);
  this.colorBuffer = this.initBufferForObj(gl, drawingInfo.colors, 3, gl.FLOAT);
  this.normalBuffer =
      this.initBufferForObj(gl, drawingInfo.normals, 3, gl.FLOAT);
  // var colorOrTexs = [];
  // for (var i = 0; i < drawingInfo.vertices.length; i++) {
  //   colorOrTexs.push(0);
  // }
  // this.colorOrTexBuffer =
  //     this.initBufferForObj(gl, new Float32Array(colorOrTexs), 1, gl.FLOAT);
  this.indexBuffer =
      this.initIndexBufferForObj(gl, drawingInfo.indices, gl.UNSIGNED_SHORT);
  this.numIndices = drawingInfo.indices.length;


  // Unbind the buffer object
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  return true;
};
Draw3D.prototype.updateByObjFile = function(gl) {
  console.log('update objfile');
  if (this.type != 'objFile') {
    console.log('Type is not objFile');
    return;
  }
  if (this.objLoad.g_objDoc != null &&
      this.objLoad.g_objDoc
          .isMTLComplete()) {  // OBJ and all MTLs are available
    this.onReadComplete(gl);
    this.objLoad.g_objDoc = null;
  }
  gl.useProgram(this.program);
  this.initAttributeVariable(gl, this.program.a_Position, this.vertexBuffer);
  this.initAttributeVariable(gl, this.program.a_Normal, this.normalBuffer);
  this.initAttributeVariable(
      gl, this.program.a_ColorOrTex, this.colorOrTexBuffer);
  if (this.texture != null) {
    this.initAttributeVariable(
        gl, this.program.a_TexCoord, this.texCoordBuffer);
    // Bind texture object to texture unit 0
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.texture);
  }
  this.initAttributeVariable(gl, this.program.a_Color, this.colorBuffer);

  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  //变换矩阵
  var modelMatrix = new Matrix4();
  // 设置光照颜色 (white)
  gl.uniform3f(this.program.u_LightColor, 1.0, 1.0, 1.0);
  // 光位置 (in the world coordinate)
  gl.uniform3f(this.program.u_LightPosition, 2.3, 4.0, 3.5);
  // 环境光
  gl.uniform3f(this.program.u_AmbientLight, 0.2, 0.2, 0.2);
  var mvpMatrix = new Matrix4();
  var normalMatrix = new Matrix4();

  mvpMatrix.setPerspective(
      this.perspective[0], this.perspective[1], this.perspective[2],
      this.perspective[3]);
  mvpMatrix.lookAt(
      this.lookat[0], this.lookat[1], this.lookat[2], this.lookat[3],
      this.lookat[4], this.lookat[5], this.lookat[6], this.lookat[7],
      this.lookat[8]);

  mvpMatrix.multiply(modelMatrix);

  normalMatrix.setInverseOf(modelMatrix);
  normalMatrix.transpose();
  gl.uniformMatrix4fv(this.program.u_ModelMatrix, false, modelMatrix.elements);

  gl.uniformMatrix4fv(this.program.u_MvpMatrix, false, mvpMatrix.elements);

  gl.uniformMatrix4fv(
      this.program.u_NormalMatrix, false, normalMatrix.elements);
  // this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
  gl.drawElements(gl.TRIANGLES, this.numIndices, this.indexBuffer.type, 0);
};
Draw3D.prototype.drawSquare = function(
    gl, vertice1, vertice2, vertice3, vertice4) {
  console.log('square');
  if (this.type != 'square') {
    console.log('Type is not square');
    return;
  }
  var vertices = new Float32Array(12);
  var normals = new Float32Array(12);
  var index = 0;
  vertices.set(vertice1, index);
  normals.set([0, 1, 0], index);
  index += 3;
  vertices.set(vertice2, index);
  normals.set([0, 1, 0], index);
  index += 3;
  vertices.set(vertice3, index);
  normals.set([0, 1, 0], index);
  index += 3;
  vertices.set(vertice4, index);
  normals.set([0, 1, 0], index);
  index += 3;

  var indices = new Uint16Array([0, 1, 2, 1, 2, 3]);
  var colorOrTexs = new Float32Array([0, 0, 0, 0]);
  if (this.texture != null) {
    colorOrTexs = new Float32Array([1, 1, 1, 1, 1]);
    var texCoords = new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]);
    this.texCoordBuffer = this.initBufferForObj(gl, texCoords, 2, gl.FLOAT);
  }
  this.vertexBuffer = this.initBufferForObj(gl, vertices, 3, gl.FLOAT);
  this.colorOrTexBuffer =
      this.initBufferForObj(gl, new Float32Array(colorOrTexs), 1, gl.FLOAT);
  this.normalBuffer = this.initBufferForObj(gl, normals, 3, gl.FLOAT);
  this.indexBuffer = this.initIndexBufferForObj(gl, indices, gl.UNSIGNED_SHORT);
  this.numIndices = indices.length;
  // Unbind the buffer object
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  this.updateSquare(gl);
};
Draw3D.prototype.updateSquare = function(gl) {
  gl.useProgram(this.program);
  this.initAttributeVariable(gl, this.program.a_Position, this.vertexBuffer);

  this.initAttributeVariable(gl, this.program.a_Normal, this.normalBuffer);
  this.initAttributeVariable(
      gl, this.program.a_ColorOrTex, this.colorOrTexBuffer);
  if (this.texture != null) {
    this.initAttributeVariable(
        gl, this.program.a_TexCoord, this.texCoordBuffer);
    // Bind texture object to texture unit 0
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.texture);
  }
  // this.initAttributeVariable(gl, this.program.a_Color, this.colorBuffer);

  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  //变换矩阵
  var modelMatrix = new Matrix4();
  // 设置光照颜色 (white)
  gl.uniform3f(this.program.u_LightColor, 1.0, 1.0, 1.0);
  // 光位置 (in the world coordinate)
  gl.uniform3f(this.program.u_LightPosition, 2.3, 4.0, 3.5);
  // 环境光
  gl.uniform3f(this.program.u_AmbientLight, 0.2, 0.2, 0.2);
  var mvpMatrix = new Matrix4();
  var normalMatrix = new Matrix4();

  mvpMatrix.setPerspective(
      this.perspective[0], this.perspective[1], this.perspective[2],
      this.perspective[3]);
  mvpMatrix.lookAt(
      this.lookat[0], this.lookat[1], this.lookat[2], this.lookat[3],
      this.lookat[4], this.lookat[5], this.lookat[6], this.lookat[7],
      this.lookat[8]);

  mvpMatrix.multiply(modelMatrix);

  normalMatrix.setInverseOf(modelMatrix);
  normalMatrix.transpose();
  gl.uniformMatrix4fv(this.program.u_ModelMatrix, false, modelMatrix.elements);

  gl.uniformMatrix4fv(this.program.u_MvpMatrix, false, mvpMatrix.elements);

  gl.uniformMatrix4fv(
      this.program.u_NormalMatrix, false, normalMatrix.elements);
  // this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
  gl.drawElements(gl.TRIANGLES, this.numIndices, this.indexBuffer.type, 0);
};
/**
  * 初次画圆柱、球
*/
Draw3D.prototype.drawCylinder = function(gl, vertice1, vertice2, r, colors) {
  if (this.type != 'cyclinder') {
    console.log('Type is not cyclinder');
    return;
  }
  this.cyclinderVertice1 = vertice1;
  this.cyclinderVertice2 = vertice2;
  //圆柱的上下两点的向量
  var vector2_1 = new Array(3);

  for (var i = 0; i < vector2_1.length; i++) {
    vector2_1[i] = vertice1[i] / vertice1[3] - vertice2[i] / vertice2[3];
  }

  var high = Math.sqrt(
      vector2_1[0] * vector2_1[0] + vector2_1[1] * vector2_1[1] +
      vector2_1[2] * vector2_1[2]);

  //初始化缓存区
  if (!this.cylinderInitVertexBuffers(gl, high, r, colors)) {
    console.log('Failed to set the vertex information');
    return;
  }
  this.updateCylinder(gl, vertice1, vertice2);
};
Draw3D.prototype.drawBall = function(gl, vertice, vector, half, r, colors) {
  if (this.type != 'ball') {
    console.log('Type is not ball');
    return;
  }
  this.ballVertice = vertice;
  this.ballVector = vector;
  //初始化缓存区
  if (!this.ballInitVertexBuffers(gl, half, r, colors)) {
    console.log('Failed to set the vertex information');
    return;
  }
  this.updateBall(gl, vertice, vector);
};
/**
 * 更新圆柱、球
 */
// Assign the buffer objects and enable the assignment
Draw3D.prototype.initAttributeVariable = function(gl, a_attribute, buffer) {
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);
  gl.enableVertexAttribArray(a_attribute);
};
Draw3D.prototype.updateCylinder = function(gl, vertice1, vertice2) {
  if (this.type != 'cyclinder') {
    console.log('Type is not cyclinder');
    return;
  }
  this.cyclinderVertice1 = vertice1;
  this.cyclinderVertice2 = vertice2;
  //切换着色器
  gl.useProgram(this.program);
  this.initAttributeVariable(gl, this.program.a_Position, this.vertexBuffer);

  this.initAttributeVariable(gl, this.program.a_Normal, this.normalBuffer);
  this.initAttributeVariable(
      gl, this.program.a_ColorOrTex, this.colorOrTexBuffer);
  if (this.texture != null) {
    this.initAttributeVariable(
        gl, this.program.a_TexCoord, this.texCoordBuffer);
    // Bind texture object to texture unit 0
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.texture);
  }
  this.initAttributeVariable(gl, this.program.a_Color, this.colorBuffer);

  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);


  //圆柱的上下两点的向量
  var vector2_1 = new Array(3);
  //从原点到圆柱中心的向量 = 上下圆心的中点坐标
  var vector0_c = new Array(3);
  for (var i = 0; i < vector2_1.length; i++) {
    vector2_1[i] = vertice1[i] / vertice1[3] - vertice2[i] / vertice2[3];
    vector0_c[i] = (vertice1[i] / vertice1[3] + vertice2[i] / vertice2[3]) / 2;
  }
  var a_zx;
  var a_z;
  if (vector2_1[0] == 0) {
    a_zx = Math.PI / 2;
    if (vector2_1[2] < 0) {
      a_zx = a_zx * (-1);
    }
  } else {
    if (vector2_1[2] == 0) {
      if (vector2_1[0] > 0) {
        a_zx = 0;
      } else {
        a_zx = Math.PI;
      }

    } else {
      a_zx = Math.atan(vector2_1[2] / vector2_1[0]);
      if (vector2_1[0] < 0) {
        a_zx += Math.PI;
      }
    }
  }

  var x_y_z = Math.sqrt(
      vector2_1[0] * vector2_1[0] + vector2_1[1] * vector2_1[1] +
      vector2_1[2] * vector2_1[2]);
  if (vector2_1[1] == 0) {
    a_z = Math.PI / 2;
  } else {
    a_z = Math.acos(vector2_1[1] / x_y_z);
  }
  //变换矩阵
  var modelMatrix = new Matrix4();
  modelMatrix.setTranslate(0, 0, 0);

  // MODEL_MATRIX为外部的变换矩阵，通过此矩阵从外部传入图形的变化
  modelMatrix.multiply(this.MODEL_MATRIX);

  modelMatrix.translate(vector0_c[0], vector0_c[1], vector0_c[2]);
  modelMatrix.rotate(180 * a_zx / Math.PI, 0, 1, 0);
  modelMatrix.rotate(180 * a_z / Math.PI, 0, 0, 1);
  modelMatrix.rotate((-1) * 180 * a_zx / Math.PI, 0, 1, 0);

  // 设置光照颜色 (white)
  gl.uniform3f(this.program.u_LightColor, 1.0, 1.0, 1.0);
  // 光位置 (in the world coordinate)
  gl.uniform3f(this.program.u_LightPosition, 2.3, 4.0, 3.5);
  // 环境光
  gl.uniform3f(this.program.u_AmbientLight, 0.2, 0.2, 0.2);


  var mvpMatrix = new Matrix4();
  var normalMatrix = new Matrix4();

  mvpMatrix.setPerspective(
      this.perspective[0], this.perspective[1], this.perspective[2],
      this.perspective[3]);
  mvpMatrix.lookAt(
      this.lookat[0], this.lookat[1], this.lookat[2], this.lookat[3],
      this.lookat[4], this.lookat[5], this.lookat[6], this.lookat[7],
      this.lookat[8]);



  mvpMatrix.multiply(modelMatrix);

  normalMatrix.setInverseOf(modelMatrix);
  normalMatrix.transpose();
  gl.uniformMatrix4fv(this.program.u_ModelMatrix, false, modelMatrix.elements);

  gl.uniformMatrix4fv(this.program.u_MvpMatrix, false, mvpMatrix.elements);

  gl.uniformMatrix4fv(
      this.program.u_NormalMatrix, false, normalMatrix.elements);
  // this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
  gl.drawElements(gl.TRIANGLES, this.numIndices, this.indexBuffer.type, 0);
};

Draw3D.prototype.updateBall = function(gl, vertice, vector) {
  if (this.type != 'ball') {
    console.log('Type is not ball');
    return;
  }
  this.ballVertice = vertice;
  this.ballVector = vector;
  //切换着色器
  gl.useProgram(this.program);
  this.initAttributeVariable(gl, this.program.a_Position, this.vertexBuffer);
  this.initAttributeVariable(gl, this.program.a_Color, this.colorBuffer);
  this.initAttributeVariable(gl, this.program.a_Normal, this.normalBuffer);

  this.initAttributeVariable(
      gl, this.program.a_ColorOrTex, this.colorOrTexBuffer);
  if (this.texture != null) {
    this.initAttributeVariable(
        gl, this.program.a_TexCoord, this.texCoordBuffer);
    // Bind texture object to texture unit 0
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.texture);
  }
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);

  var a_zx;
  var a_z;
  ;
  if (vector[0] == 0) {
    a_zx = Math.PI / 2;
    if (vector[2] < 0) {
      a_zx = a_zx * (-1);
    }
  } else {
    if (vector[2] == 0) {
      if (vector[0] > 0) {
        a_zx = 0;
      } else {
        a_zx = Math.PI;
      }

    } else {
      a_zx = Math.atan(vector[2] / vector[0]);
      if (vector[0] < 0) {
        a_zx += Math.PI;
      }
    }
  }
  var x_y_z = Math.sqrt(
      vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
  if (vector[1] == 0) {
    a_z = Math.PI / 2;
  } else {
    a_z = Math.acos(vector[1] / x_y_z);
  }
  var modelMatrix = new Matrix4();
  modelMatrix.setTranslate(0, 0, 0);

  modelMatrix.multiply(this.MODEL_MATRIX);

  modelMatrix.translate(vertice[0], vertice[1], vertice[2]);
  modelMatrix.rotate(180 * a_zx / Math.PI, 0, 1, 0);
  modelMatrix.rotate(180 * a_z / Math.PI, 0, 0, 1);
  modelMatrix.rotate((-1) * 180 * a_zx / Math.PI, 0, 1, 0);

  // 设置光照颜色 (white)
  gl.uniform3f(this.program.u_LightColor, 1.0, 1.0, 1.0);
  // 光位置 (in the world coordinate)
  gl.uniform3f(this.program.u_LightPosition, 2.3, 4.0, 3.5);
  // 环境光
  gl.uniform3f(this.program.u_AmbientLight, 0.2, 0.2, 0.2);


  var mvpMatrix = new Matrix4();
  var normalMatrix = new Matrix4();

  mvpMatrix.setPerspective(
      this.perspective[0], this.perspective[1], this.perspective[2],
      this.perspective[3]);
  mvpMatrix.lookAt(
      this.lookat[0], this.lookat[1], this.lookat[2], this.lookat[3],
      this.lookat[4], this.lookat[5], this.lookat[6], this.lookat[7],
      this.lookat[8]);

  mvpMatrix.multiply(modelMatrix);

  normalMatrix.setInverseOf(modelMatrix);
  normalMatrix.transpose();

  gl.uniformMatrix4fv(this.program.u_ModelMatrix, false, modelMatrix.elements);

  gl.uniformMatrix4fv(this.program.u_MvpMatrix, false, mvpMatrix.elements);

  gl.uniformMatrix4fv(
      this.program.u_NormalMatrix, false, normalMatrix.elements);
  // this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
  gl.drawElements(gl.TRIANGLES, this.numIndices, this.indexBuffer.type, 0);
};
/**
 * 缓存区初始化
 */

Draw3D.prototype.cylinderInitVertexBuffers = function(gl, high, r, color) {

  // 上下两个圆面的y坐标
  var y1 = high / 2;
  var y2 = (-1) * high / 2;

  var num = 240;                              //一个园面的扇形数
  var vertice_num = ((num + 1) * 3 + 1) * 2;  //点数量
  //点位置
  var vertices = new Float32Array(vertice_num * 3);
  //点颜色
  var colors = new Float32Array(vertice_num * 3);
  //法向量
  var normals = new Float32Array(vertice_num * 3);
  //点索引
  var indices = new Uint16Array(num * 4 * 3);


  //计算圆上的点
  //上下两个圆面的圆心
  var index = 0;
  var tmpVertice = new Array();
  var tmpNormal1 = new Array();
  var tmpNormal2 = new Array();

  tmpVertice[0] = 0;
  tmpVertice[1] = y1;
  tmpVertice[2] = 0;
  vertices.set(tmpVertice, index);
  colors.set(color, index);
  normals.set([0, 1, 0], index);
  index += 3;

  tmpVertice[1] = y2;
  vertices.set(tmpVertice, index);
  colors.set(color, index);
  normals.set([0, -1, 0], index);
  index += 3;
  //圆上的点
  var aa = 0;
  var a = (1 / num) * Math.PI;
  tmpNormal1[1] = 0;
  tmpNormal2[1] = 0;
  for (var i = 0; i < num + 1; i++) {
    aa = (i / num) * 2 * Math.PI;
    tmpNormal1[0] = Math.cos(aa - a);
    tmpNormal1[2] = Math.sin(aa - a);
    tmpNormal2[0] = Math.cos(aa + a);
    tmpNormal2[2] = Math.sin(aa + a);

    tmpVertice[0] = r * Math.cos(aa);
    tmpVertice[1] = y1;
    tmpVertice[2] = r * Math.sin(aa);


    vertices.set(tmpVertice, index);
    colors.set(color, index);
    normals.set(tmpNormal1, index);
    index += 3;
    vertices.set(tmpVertice, index);
    colors.set(color, index);
    normals.set([0, 1, 0], index);
    index += 3;
    vertices.set(tmpVertice, index);
    colors.set(color, index);
    normals.set(tmpNormal2, index);
    index += 3;

    tmpVertice[1] = y2;
    vertices.set(tmpVertice, index);
    colors.set(color, index);
    normals.set(tmpNormal1, index);
    index += 3;
    vertices.set(tmpVertice, index);
    colors.set(color, index);
    normals.set([0, -1, 0], index);
    index += 3;
    vertices.set(tmpVertice, index);
    colors.set(color, index);
    normals.set(tmpNormal2, index);
    index += 3;
  }

  //计算三角形的组合
  var index = 0;
  var tIndices = new Array(3);

  for (var i = 3; i < vertice_num - 6; i += 6) {
    tIndices[0] = 0;
    tIndices[1] = i;
    tIndices[2] = i + 6;
    indices.set(tIndices, index);
    index += 3;

    tIndices[0] = i + 1;
    tIndices[1] = i + 4;
    tIndices[2] = i + 5;
    indices.set(tIndices, index);
    index += 3;

    tIndices[0] = i + 4;
    tIndices[1] = i + 5;
    tIndices[2] = i + 8;
    indices.set(tIndices, index);
    index += 3;

    tIndices[0] = 1;
    tIndices[1] = i + 3;
    tIndices[2] = i + 9;
    indices.set(tIndices, index);
    index += 3;
  }
  var colorOrTexs = [];
  if (this.texture != null) {
    //颜色或纹理判断值
    var tmpColorOrTex = 1.0;

    //纹理图片坐标
    var texCoords = new Float32Array(vertice_num * 2);
    var texH, texL;
    if (high > (2 * Math.PI * r)) {
      texH = 1;
      texL = (2 * Math.PI * r) / high;
    } else {
      texH = high / (2 * Math.PI * r);
      texL = 1;
    }
    var tmpTexCoord = new Array();
    var tex_index = 0;
    tmpTexCoord[0] = 0;
    tmpTexCoord[1] = 0;
    texCoords.set(tmpTexCoord, tex_index);
    colorOrTexs.push(1);
    tex_index += 2;
    texCoords.set(tmpTexCoord, tex_index);
    colorOrTexs.push(1);
    tex_index += 2;
    for (var i = 0; i < num + 1; i++) {
      tmpTexCoord[0] = i * texL / (num + 1);
      tmpTexCoord[1] = texH;
      texCoords.set(tmpTexCoord, tex_index);
      colorOrTexs.push(tmpColorOrTex);
      tex_index += 2;
      texCoords.set(tmpTexCoord, tex_index);
      colorOrTexs.push(1);
      tex_index += 2;
      texCoords.set(tmpTexCoord, tex_index);
      colorOrTexs.push(tmpColorOrTex);
      tex_index += 2;

      tmpTexCoord[1] = 0;
      texCoords.set(tmpTexCoord, tex_index);
      colorOrTexs.push(tmpColorOrTex);
      tex_index += 2;
      texCoords.set(tmpTexCoord, tex_index);
      colorOrTexs.push(1);
      tex_index += 2;
      texCoords.set(tmpTexCoord, tex_index);
      colorOrTexs.push(tmpColorOrTex);
      tex_index += 2;
    }
    this.texCoordBuffer = this.initBufferForObj(gl, texCoords, 2, gl.FLOAT);
  } else {
    for (var i = 0; i < vertice_num; i++) {
      colorOrTexs.push(0);
    }
  }
  //将数据传入缓存区，并交给buffer对象保存相关数据
  this.vertexBuffer = this.initBufferForObj(gl, vertices, 3, gl.FLOAT);
  this.colorBuffer = this.initBufferForObj(gl, colors, 3, gl.FLOAT);
  this.normalBuffer = this.initBufferForObj(gl, normals, 3, gl.FLOAT);
  this.colorOrTexBuffer =
      this.initBufferForObj(gl, new Float32Array(colorOrTexs), 1, gl.FLOAT);

  this.indexBuffer = this.initIndexBufferForObj(gl, indices, gl.UNSIGNED_SHORT);
  this.numIndices = indices.length;
  // Unbind the buffer object
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

  return true;
};
Draw3D.prototype.ballInitVertexBuffers = function(gl, half, r, color) {
  var SPHERE_DIV = 50;
  var vertice_num = (SPHERE_DIV + 1) * (SPHERE_DIV + 1);
  var colors = new Float32Array((SPHERE_DIV + 1) * (SPHERE_DIV + 1) * 3);
  var i, ai, si, ci;
  var j, aj, sj, cj;
  var p1, p2;

  var positions = [];
  var indices = [];

  //判断值
  var colorOrTexs = [];
  var index = 0;
  if (this.texture == null) {
    // Generate coordinates
    for (j = 0; j <= SPHERE_DIV; j++) {
      aj = j * Math.PI * half / SPHERE_DIV;
      sj = r * Math.sin(aj);
      cj = r * Math.cos(aj);
      for (i = 0; i <= SPHERE_DIV; i++) {
        ai = i * 2 * Math.PI / SPHERE_DIV;
        si = Math.sin(ai);
        ci = Math.cos(ai);

        positions.push(si * sj);  // X
        positions.push(cj);       // Y
        positions.push(ci * sj);  // Z
        colorOrTexs.push(0);
        colors.set(color, index);
        index += 3;
      }
    }
  } else {
    // Generate coordinates
    var texCoords = [];
    for (j = 0; j <= SPHERE_DIV; j++) {
      aj = j * Math.PI * half / SPHERE_DIV;
      sj = r * Math.sin(aj);
      cj = r * Math.cos(aj);
      for (i = 0; i <= SPHERE_DIV; i++) {
        ai = i * 2 * Math.PI / SPHERE_DIV;
        si = Math.sin(ai);
        ci = Math.cos(ai);

        positions.push(si * sj);  // X
        positions.push(cj);       // Y
        positions.push(ci * sj);  // Z

        texCoords.push(aj / r);
        texCoords.push(sj * sj / r);

        colorOrTexs.push(1);
        colors.set(color, index);
        index += 3;
      }
    }
    this.texCoordBuffer =
        this.initBufferForObj(gl, new Float32Array(texCoords), 2, gl.FLOAT);
  }

  // Generate indices
  for (j = 0; j < SPHERE_DIV; j++) {
    for (i = 0; i < SPHERE_DIV; i++) {
      p1 = j * (SPHERE_DIV + 1) + i;
      p2 = p1 + (SPHERE_DIV + 1);

      indices.push(p1);
      indices.push(p2);
      indices.push(p1 + 1);

      indices.push(p1 + 1);
      indices.push(p2);
      indices.push(p2 + 1);
    }
  }

  //将数据传入缓存区，并交给buffer对象保存相关数据
  this.vertexBuffer =
      this.initBufferForObj(gl, new Float32Array(positions), 3, gl.FLOAT);

  this.colorBuffer = this.initBufferForObj(gl, colors, 3, gl.FLOAT);
  this.normalBuffer =
      this.initBufferForObj(gl, new Float32Array(positions), 3, gl.FLOAT);
  this.colorOrTexBuffer =
      this.initBufferForObj(gl, new Float32Array(colorOrTexs), 1, gl.FLOAT);
  this.indexBuffer = this.initIndexBufferForObj(
      gl, new Uint16Array(indices), gl.UNSIGNED_SHORT);
  this.numIndices = indices.length;
  // Unbind the buffer object
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

  return true;
};
/**
 * 缓存区创建
 */
Draw3D.prototype.initBufferForObj = function(gl, data, num, type) {
  var buffer = gl.createBuffer();  // Create a buffer object
  if (!buffer) {
    console.log('Failed to create the buffer object');
    return null;
  }
  // Write date into the buffer object
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

  // Keep the information necessary to assign to the attribute variable later
  buffer.num = num;
  buffer.type = type;
  return buffer;
};
Draw3D.prototype.initIndexBufferForObj = function(gl, data, type) {
  var buffer = gl.createBuffer();
  　  // Create a buffer object
      if (!buffer) {
    console.log('Failed to create the buffer object');
    return null;
  }
  // Write date into the buffer object
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);

  buffer.type = type;

  return buffer;
};

Draw3D.prototype.configureTexture = function(gl, image) {
  this.texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, this.texture);
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
  gl.generateMipmap(gl.TEXTURE_2D);
  gl.texParameteri(
      gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  // Prevents s-coordinate wrapping (repeating).
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  // Prevents t-coordinate wrapping (repeating).
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.uniform1i(gl.getUniformLocation(this.program, 'u_Sampler'), 0);
};